/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 */

import { getUrl, URL_KEY_ENUM } from '@ohos/hvigor-logger';
import fs from 'fs';
import path from 'path';

import { FileSet, HvigorLogger, Input } from '@ohos/hvigor';
import { getOsLanguage } from '@ohos/hvigor-common';
import fse from 'fs-extra';

import { OptCompressionBuilder } from '../builder/opt-compression-builder.js';
import { BuildArtifactConst, ResToolInputTypeConst } from '../const/build-directory-const.js';
import { CommonConst, DefaultTargetConst } from '../const/common-const.js';
import { ProjectModelImpl } from '../model/project/project-model-impl.js';
import { InjectUtil } from '../utils/inject-util.js';
import { AbstractProcessResource } from './abstract/abstract-process-resource.js';
import { TaskNames } from './common/task-names.js';
import { TargetTaskService } from './service/target-task-service.js';
import { UnitTestProcessProfile } from './unitTest/unit-test-process-profile.js';

import Task = TaskNames.Task;

const ohosTestTargetName = DefaultTargetConst.OHOS_TEST_TARGET;

const _log = HvigorLogger.getLogger('process-resource');

/**
 * Stage 模型用于处理和生成用文件方式编译资源的中间文件
 *
 * @since 2022/9/8
 */
export class ProcessResource extends AbstractProcessResource {
  optCompressionBuilder: OptCompressionBuilder;
  protected optCompressionFilePath: string;

  constructor(taskService: TargetTaskService) {
    super(taskService, Task.PROCESS_RESOURCE);
    this.resConfigFilePath = path.resolve(this.outputDir!, CommonConst.RES_CONFIG_FILE);
    this.optCompressionFilePath = path.resolve(this.outputDir!, CommonConst.OPT_COMPRESSION_FILE);
    this.optCompressionBuilder = this.getOptCompressionBuilder();
  }

  initTaskDepends() {
    super.initTaskDepends();
    if (InjectUtil.isUnitTestProcess()) {
      this.declareDepends(UnitTestProcessProfile.name);
    }
  }

  protected beforeTask() {
    super.beforeTask();

    if (fse.existsSync(this.optCompressionFilePath)) {
      fse.removeSync(this.optCompressionFilePath);
    }
  }

  declareInputs() {
    const inputs = super.declareInputs();
    inputs.set(this.optCompressionFilePath, JSON.stringify(this.optCompressionBuilder.getOptCompressionObj()));
    // resource_str目录存在与否应作为此任务增量，否则此任务跳过resconfig文件不更新会导致问题
    inputs.set('resource_str', fse.existsSync(path.resolve(this.pathInfo.getIntermediatesRes(), 'resource_str')));
    return inputs;
  }

  @Input() private get ignoreResourcePattern() {
    return this.targetService.getBuildOption().resOptions?.ignoreResourcePattern;
  }

  protected doTaskAction() {
    this.restoolConfigBuilder.addInputDir(this.pathInfo.getResourceStr(), ResToolInputTypeConst.HAR);
    const optCompression = this.optCompressionBuilder.getOptCompressionObj();
    fse.outputJSONSync(this.optCompressionFilePath, optCompression);
    this.restoolConfigBuilder.addCompression(this.optCompressionFilePath);

    // 超纹理压缩性能优化,配置资源编译线程数写入resConfig, 用户没配置则不需要写入信息
    this.restoolConfigBuilder.setResCompileThread(this.processResCompileThreads());

    // 配置资源打包的过滤规则写入resConfig, 用户没配置则不需要写入信息
    this.restoolConfigBuilder.setIgnoreResourcePattern(this.processIgnoreResourcePattern(this.ignoreResourcePattern));

    // 给 restoolConfigBuilder 加上 compression 属性后再调用 super.doTaskAction 写 resConfig.json 文件
    super.doTaskAction();
  }

  declareOutputFiles(): FileSet {
    const fileSet = super.declareOutputFiles();
    fileSet.addEntry(this.optCompressionFilePath, { isDirectory: false });
    return fileSet;
  }

  private getAppResourceDir() {
    const curProduct = this.targetData.getProduct();
    if (curProduct.resource !== undefined && curProduct.resource.directories.length !== 0) {
      return path.resolve(this.projectModel.getProjectDir(), curProduct.resource?.directories[0]);
    }
    return (this.projectModel as ProjectModelImpl).getAppRes().getResourcePath();
  }

  @Input() private get includeAppScopeRes() {
    return this.targetService.getBuildOption().resOptions?.includeAppScopeRes;
  }

  initCommandBuilder() {
    if (this.service.getModuleModel().isHapModule() || (this.service.getModuleModel().isHspModule() && this.includeAppScopeRes !== false) || this.targetName === ohosTestTargetName) {
      this.restoolConfigBuilder.addInputDir(this.getAppResourceDir(), 'App');
    }
    const bundleName: string = (this.projectModel as ProjectModelImpl).getAppRes().getAppResOpt().app.bundleName;
    const idsPath = path.resolve(this.pathInfo.getIntermediatesRes(), 'ids_map');
    this.restoolConfigBuilder
      .addJsonFile(this.processedJson!)
      .addModulePackName(bundleName)
      .addOutputDir(this.outputDir!)
      .addResTable(path.resolve(this.pathInfo.getGenerateSourceR(), BuildArtifactConst.RESOURCE_TABLE_H))
      .addIdsPath(idsPath)
      .addDefinedIds(path.resolve(idsPath, 'id_defined.json')); // 即使此文件不存在，restool也不会报错，而是认为这个配置不生效

    // HOS工程会单独传递HOS toolchain路径给restool
    if (!this.sdkInfo.isOhos) {
      const definedSysIdsPath = path.resolve(this.sdkInfo.getHosToolchainsDir(), 'id_defined.json');
      if (fs.existsSync(definedSysIdsPath)) {
        this.restoolConfigBuilder.addDefinedSysIds(definedSysIdsPath);
      }
    }
    if (this.isEnabledIconCheck()) {
      // 资源编译图标检测
      this.restoolConfigBuilder.setIconCheck(true);
    }

    if (this.targetData.getTargetName() === ohosTestTargetName) {
      // ohosTest资源编译时添加需要额外的编译的Resources
      this.addOhosTestExtraCompilationResources(this.restoolConfigBuilder);
      this.addIntermediatesSrcResource(this.restoolConfigBuilder, this.moduleModel.getSourceRootByTargetName(ohosTestTargetName));
    }
  }

  getOptCompressionBuilder() {
    const mergedConfig = this.targetService.getBuildOption().resOptions?.compression;

    /**
     * 当os是harmonyOS，且media开关不为false或者识别到filters选项，同时识别到当前模块为hsp或者hap，则hvigor触发纹理超压缩处理
     */
    const isEnableCompression =
      this.targetData.isHarmonyOS() &&
      (mergedConfig?.media?.enable || (Array.isArray(mergedConfig?.filters) && mergedConfig!.filters.length > 0)) &&
      (this.service.getModuleModel().isHapModule() || this.service.getModuleModel().isHspModule());

    const optCompressionBuilder = new OptCompressionBuilder();

    // 即使不开启纹理超压缩功能，也需要生成 opt-compression.json 并填入 extensionPath 字段
    optCompressionBuilder.setExtensionPath(this.sdkInfo.getLibimageTranscoderShared());

    if (isEnableCompression) {
      /**
       * 纹理超压缩功能目前无法处理分层图标，只要开启了该功能就会输出这段提示说明，指导用户添加配置项排除分层图标文件
       */
      const country = getOsLanguage();
      const url = getUrl(URL_KEY_ENUM.DEVELOPER_URL);
      const httpPath = `${url}/consumer/${country}/doc/harmonyos-guides-V5/ide-hvigor-build-profile-V5`;
      _log.warn(
        'You have enabled the resource compression function, which will change the resource file name and data format. In some cases, ' +
          'you may experience problems with abnormal image displaying, in particular the disappearance of the layered launcher icon.\n' +
          'You can set the filter parameters to exclude these files, or to include the files you just need.\n' +
          `For details, see compression option in ${httpPath}`,
      );

      /**
       * 超纹理的资源目录取 resConfig.json 中的 applicationResource, moduleResources, dependencies
       * 但 applicationResource 需要在调用 initCommandBuilder 时才会去获取，因此当前是 undefined
       * 需要先手动去获取一次 applicationResource
       */
      const resourceDirArr = [...this.restoolConfigBuilder.getResourceDir(), this.getAppResourceDir()];
      optCompressionBuilder.setResourceDirArr(resourceDirArr).setCompressionConfig(mergedConfig);
    }

    return optCompressionBuilder;
  }
}
